03 - Przetwarzanie danych tekstowych
Podstawy przetwarzania danych
Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej
Ćwiczenie laboratoryjne 3: przetwarzanie danych tekstowych
Powrót do spisu treści ćwiczeń laboratoryjnych
Przetwarzanie danych tekstowych
Przetwarzanie danych tekstowych jest jednym z fundamentalnych zadań programistycznych. Jest ono niezbędne w większości sytuacji wymagających długotrwałego przechowywania informacji, także po zakończeniu działania skryptu.
Obsługa plików
Aby rozpocząć pracę z plikiem tekstowym w pierwszej kolejności należy go otworzyć. W pythonie ogranicza się to do skorzystania z wbudowanej funkcji open()
. Zwraca ona uchwyt do pliku. Pierwszym argumentem przyjmowanym przez tę funkcję jest ścieżka do pliku. Domyślnie ścieżka zaczyna się od katalogu roboczego, czyli katalogu w którym uruchomiony został skrypt. Jeżeli interesujący nas plik znajduje się w tym samym katalogu jako argument podajemy jedynie jego nazwę.
open("text_file.txt")
Jeżeli plik znajduje się w innej lokalizacji, jako argument możemy podać ścieżkę bezwzględną. W systemie operacyjnym Windows zaczyna się ona od litery dysku, np. C:\
a w rodzinie systemów operacyjnych Linux będzie to katalog główny /
. Należy przy tym pamiętać, że użycie ścieżki bezwzględnej znacząco ogranicza przenośność naszego skryptu. Następnym argumentem funkcji open()
jest tryb otwarcia pliku. Domyślnym trybem jest tryb odczytu pliku tekstowego r
lub rt
.
Znak | Znaczenie |
---|---|
"r" |
Read - Domyślna wartość. Otwiera plik do odczytu, zwraca błąd jeżeli plik nie istnieje. |
"w" |
Write - Otwiera plik do zapisu, ucina zawartość, utworzy plik jeżeli nie istnieje. |
"x" |
Exclusive creation - Otwiera plik do utworzenia, zwraca błąd jeżeli plik istnieje. |
"a" |
Append - Otwiera plik w trybie do dopisywania, utworzy plik jeżeli nie istnieje. |
"b" |
Binary - Otwiera plik w trybie binarnym. |
"t" |
Text - Domyślna wartość. Otwiera plik w trybie tekstowym. |
Więcej informacji o funkcji można znaleźć tutaj.
Odczyt danych
Jak zostało wspomniane w podrozdziale Obsługa plików, funkcja open()
nie zwraca zawartości pliku a jedynie uchwyt do niego. Do odczytania zawartości można użyć metod read()
i readline()
. Pierwsza z nich odczyta całość pliku, a druga będzie odczytywać kolejne linie tekstu. Ostatnia metoda to close()
. Dobrą praktyką jest użycie jej kiedy praca z plikiem zostanie zakończona. Jest to szczególnie istotne przy zapisywaniu danych do pliku, ponieważ jego zamknięcie gwarantuje, że skrypt nie zakończy działania w trakcie tego procesu. Aby wypróbować poniższy przykład pobierz file.txt.
file = open("file.txt")
= file.read()
contents print(contents)
file.close()
print("---")
file = open("file.txt")
= file.readline()
line1 = file.readline()
line2 print(line1)
print(line2)
file.close()
Jako opcjonalny argument w obu metodach sprecyzować można ilość bajtów do odczytania. Aby upewnić się, że plik zawsze zostanie poprawnie zamknięty, a przy okazji poprawić czytelność kodu, użyć można wyrażenia with
. Przy jego użyciu plik zostanie zamknięty automatycznie po zakończeniu wykonywania bloku kodu.
with open("file.txt") as file:
= file.read()
contents print(contents)
W przypadku nieistniejącego pliku python zatrzyma wykonywanie skryptu i wyświetli w konsoli błąd. Aby temu zapobiec użyć można bloków try-except
. Except wywoła się tylko wtedy, kiedy zwróconym przez skrypt błędem będzie FileNotFoundError
. Więcej wbudowanych typów błędów.
try:
with open("file.txt") as file:
file.read()
except FileNotFoundError:
print("file.txt nie istnieje")
💥 Zadanie 1 💥
Wykorzystaj powyższy przykład i pętlę aby odczytać całość pliku broken_sentence.txt i scalić ze sobą kolejne linie. Kiedy readline()
osiągnie koniec pliku zwróci pusty string, wykorzystaj to w swojej pętli.
Podpowiedź
Jak można zaobserwować metoda readline()
zwraca nam także znak nowej linii \n
. Usunąć go można na przykład przy pomocy metody replace()
która jako pierwszy z argumentów przyjmuje string do wymiany, a drugim jest string na który zostanie zamieniony, w tym przypadku powinien on pozostać pusty.
Zapis danych
Do zapisania danych do pliku użyć można metody write()
. Należy przy tym pamiętać o wybraniu odpowiedniego trybu otwarcia pliku.
with open("file.txt", "w") as file:
file.write("I'm the file contents now")
Użycie powyższego zapisu spowoduje ucięcie oryginalnej zawartości pliku już w momencie jego otwarcia. Aby ją zachować używa się między innymi trybu append.
with open("file.txt", "a") as file:
file.write("I'm at the end of the file")
💥 Zadanie 2 💥
Napisz skrypt który sprawdzi czy plik user_data.txt
istnieje, jeżeli tak odczyta jego zawartość i wyświetli w konsoli. Jeżeli nie, zostanie on utworzony, a następnie przez konsolę użytkownik skryptu podawać będzie kolejne linie zawartości tak długo aż nie poda “stop”.
Parsowanie danych tekstowych
Może się zdarzyć, że odczytanie danych z pliku będzie wymagało przetworzenia ich w określony sposób. Jeżeli plik zawierać będzie nagłówek, to powinien on zostać zignorowany przy wczytywaniu danych. Poszczególne wartości zapisane w pliku mogą być oddzielone od siebie różnymi separatorami, spacją, przecinkiem, średnikiem. W takiej sytuacji należy napisać parser, który rozbije surowy tekst na przydatne fragmenty, gotowe do zapisania w strukturach pythonowych. Poniżej przedstawiono prosty przykład parsera wczytującego dane z pliku custom_data.txt.
file = open("custom_data.txt")
= {}
data_dict
= 1
skip_lines for line in file:
if skip_lines <= 0:
= line.split(sep=';')
usr_id, name, surname, grade = {"Name": name, "Surname": surname, "Grade": float(grade)}
data_dict[usr_id] else:
-= 1
skip_lines
file.close()
Jeżeli pracujemy zarówno na stringach jak i uchwytach do plików i zależy nam na przetwarzaniu ich w podobny sposób, string można zamienić na obiekt IO przy pomocy funkcji io.StringIO()
. Należy pamiętać przy tym o imporcie wbudowanej biblioteki import io
.
💥 Zadanie 3 💥
Pobierz plik weather_data.yaml, następnie wczytaj z niego dane. Kluczem rekordów jest data. Oblicz i wyświetl średnią temperaturę dla tego okresu, oraz znajdź i wyświetl dzień z najniższą wilgotnością.
Podpowiedź
Metoda split()
z argumentem domyślnym None
spowoduje potraktowanie wszystkich białych znaków jak separatorów. Następujące po sobie separatory zostaną zgrupowane. Zdefiniowanie separatora innego niż None
spowoduje potraktowanie pustych stringów pomiędzy separatorami jako osobnych wartości.
Format CSV
Format csv (ang. comma-separated values) jest formatem przechowywania danych w plikach tekstowych. Jak sugeruje jego nazwa poszczególne wartości oddzielone są od siebie przecinkiem, choć zawarty w bibliotece standardowej moduł csv pozwala na wybranie innego separatora. Rekordy oddzielone są od siebie znakiem nowej linii. Aby zacząć pracę z modułem csv należy go najpierw zaimportować.
import csv
Aby odczytać zawartość pliku w formacie csv używa się metody csv reader()
. Przy użyciu pętli for obiekt reader zwróci rzędy w formie listy elementów. Przykładowy plik file.csv
with open("file.csv") as file:
= csv.reader(file)
data for row in data:
print(row)
Jeżeli separator nie jest domyślnym przecinkiem, niezbędne jest podanie go jako atrybut metody reader()
with open("file.csv") as file:
= csv.reader(file, delimiter='.')
data for row in data:
for value in row:
print(value)
Do zapisywania danych w formacie csv służy metoda writer()
, po którego utworzeniu korzystamy z metody writerow()
, do której w argumencie podajemy listę wartości. Metoda ta dodaje znak nowej linii po każdym wywołaniu, co powoduje problem w przypadku domyślnego otwarcia pliku do zapisu, które również dodaje kolejny znak nowej linii przy każdym zapisie do pliku. Z tego powodu należy przy otwarciu pliku zastąpić znak nowej linii pustą zmienną string, nadpisując argument newline
.
= [12, 23, 34]
row_to_save
with open("file.csv", 'w', newline='') as file:
= csv.writer(file, delimiter=';')
csv_writer 'A', 'B', 'C'])
csv_writer.writerow([ csv_writer.writerow(row_to_save)
Więcej informacji na temat korzystania z modułu csv znaleźć można tutaj.
💥 Zadanie 4 💥
Zapisz poniższe dane do formatu csv, uwzględniając nagłówek z nazwami kolumn. Dobierz separator tak, aby współgrał z danymi w tabeli.
= ["Date", "Product", "Units Sold", "Price per Unit"]
header = [
sales_data "2023-10-01", "Laptop", 5, 1200.0),
("2023-10-01", "Phone", 10, 500.0),
("2023-10-02", "Laptop", 3, 1200.0),
("2023-10-02", "Phone", 7, 500.0),
("2023-10-03", "Laptop", 4, 1200.0),
("2023-10-03", "Phone", 12, 500.0),
( ]
Podpowiedź
Aby przy odczytywaniu csv pominąć pierwszą linię z nagłówkiem możemy, tak jak dla innych iterowalnych obiektów w pythonie, wywołać funkcję next()
. Reader przejdzie wtedy do kolejnej linii pliku.
Format JSON
Kolejnym popularnym formatem przechowywania danych w plikach tekstowych jest JSON (ang. JavaScript Object Notation). Choć nazwa sugeruje powiązanie z językiem JavaScript, w praktyce obsługiwany jest on przez wiele języków programowania, w tym python. Strukturą przypomina zawarty w pythonie słownik. Do jego obsługi zaimportować należy wbudowany w bibliotekę standardową moduł json
.
import json
Aby wczytać plik używa się metody load()
. W tym przypadku zwróci ona słownik, dlatego do poszczególnych wartości należy odwołać się według klucza. Zwrócony przez load()
obiekt może być jednym z tych wypisanych na poniższej liście. - dict - list - str - int - float - True - False - None
Przykładowy plik json do odczytania.
with open("employees.json") as file:
= json.load(file)
data print(data)
print(data[0]["name"])
Oprócz load()
istnieje również metoda loads()
, która odczytuje json z obiektu string, zamiast z pliku bądź obiektu json. Dane w formacie json zapisujemy jak inne pliki tekstowe, metodą write()
, ale przed zapisem słownik musi być odpowiednio sformatowany przy pomocy metody dumps()
. Nie mylić z metodą dump()
, która konwertuje obiekty pythonowe na obiekt json. Do stringu w formacie JSON przekonwertować możemy następujące obiekty: - dict - list - tuple - str - int - float - True - False - None
= {
student "student_name": "John",
"student_surname": "Paul",
"age": 24,
"subject_list": [
"subject": "Flexible manufacturing systems", "points": 77.5, "grade": 4.0},
{"subject": "Basics of data processing", "points": 21.00, "grade": 2.0}
{
]
}
with open("file.json", 'w') as file:
= json.dumps(student)
data file.write(data)
Więcej informacji na temat korzystania z modułu json znaleźć można tutaj.
💥 Zadanie 5 💥
Otwórz plik employees.json, do którego użytkownik skryptu doda przez konsolę kolejnego pracownika. Następnie nadpisz plik json z nowym pracownikiem.
Zadanie dla chętnych
Napisz funkcję odczytującą dane z pliku tekstowego. Powinna ona sama znajdować ile linii nagłówka zawiera plik i jakiego separatora używa, jako argument przyjmując jedynie ścieżkę do pliku. Przykładowe pliki do załadowania: sample1.txt, sample2.txt, sample3.txt.